﻿using System.Reflection;
using CTS.Com.Domain.Exceptions;
using CTS.Com.Domain.Validate.Attr;
using CTS.Com.Domain.Validate.Model;

namespace CTS.Com.Domain.Helper
{
    public static class ValidateHelper
    {
        private static string PATH_CONFIG = "CTS.Com.ValidateRules.xml";

        public static void Validate(object obj)
        {
            // Check null
            if (obj == null) return;

            // Get properties
            var props = obj.GetType().GetProperties(
                BindingFlags.Public | BindingFlags.Instance);

            // Get collection rule
            var stream = typeof(ValidateHelper).Assembly.GetManifestResourceStream(PATH_CONFIG);
            var rules = XmlHelper.Deserialize<Rules>(stream);

            // Browse by property
            object[] attrs = null;
            object value = null;
            foreach (var prop in props) {
                // Get validation attributes
                attrs = prop.GetCustomAttributes(typeof(AbstractValidation), true);

                // Check has validation attributes
                if (attrs.Length == 0) continue;

                // Get value property
                value = prop.GetValue(obj, null);

                // Get attribute
                var attr = attrs[0];
                // Get attribute type
                var attrType = attr.GetType();

                // Domain validation
                if (attrType == typeof(DomainValidation)
                    || attrType.BaseType == typeof(DomainValidation)) {
                    // Convert domain validation
                    var valAttr = attr as DomainValidation;
                    // Get rule by name
                    var rule = ContextHelper.ValidateRules[valAttr.RuleName];
                    if (rule == null) rule = rules[valAttr.RuleName];
                    // Check rule exist
                    if (rule == null) {
                        throw new ExecuteException("E_MSG_00007", valAttr.RuleName);
                    }
                    // Validate
                    valAttr.IsValid(value, rule);
                }
                    // List validation
                else if (attrType == typeof(ListValidation)
                    || attrType.BaseType == typeof(ListValidation)) {
                    // Convert list validation
                    var valAttr = attr as ListValidation;
                    // Check type valid
                    if (prop.PropertyType.Namespace != "System.Collections.Generic") {
                        throw new ExecuteException("E_MSG_00008", valAttr.MessageParam);
                    }
                    // Validate
                    valAttr.IsValid(value, null);
                }
                    // Object validation
                else if (attrType == typeof(ObjectValidation)
                    || attrType.BaseType == typeof(ObjectValidation)) {
                    // Convert list validation
                    var valAttr = attr as ObjectValidation;
                    // Check type valid
                    if (!prop.PropertyType.IsClass) {
                        throw new ExecuteException("E_MSG_000021", valAttr.MessageParam);
                    }
                    // Validate
                    valAttr.IsValid(value, null);
                }
            }
        }
    }
}
